<?php

namespace App\Admin\Models;

use App\Admin\Exceptions\SystemModelException;
use App\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\SoftDeletes;
use Throwable;
use Exception;

class SystemModel extends Model
{
    use SoftDeletes;
    
    const TYPE_INPUT = 'input';
    const TYPE_INPUT_JSON = 'input_json';
    const TYPE_TEXTAREA = 'textarea';
    const TYPE_FILE = 'file';
    const TYPE_SINGLE = 'single';
    const TYPE_MULTIPLE = 'multiple';
    const TYPE_OTHER = 'other';
    const TYPE_EDITOR = 'editor';
    const TYPE_DATE = 'date';
    const TYPE_TIME = 'time';
    const TYPE_PASSWORD = 'password';
    const TYPE_DATETIME = 'datetime';
    const TYPE_DYNAMIC_INPUT = 'dynamic_input';
    const TYPE_DYNAMIC_TEXTAREA = 'dynamic_textarea';
    const TYPE_CASCADER = 'cascader';
    const TYPE_SELECT_TREE = 'select_tree';
    const CACHE_KEY = 'admin_config';
    const CONFIG_KEY = 'admin';

    // 表单页场景的字段类型
    public static $inputTypeMap = [
        self::TYPE_TEXTAREA => '多行文本域',
        self::TYPE_MULTIPLE => '多选',
        self::TYPE_DATE => '日期选择器',
        self::TYPE_TIME => '时间选择器',
        self::TYPE_FILE => '文件上传',
        self::TYPE_OTHER => '其他',
        self::TYPE_EDITOR => '编辑器',
        self::TYPE_PASSWORD => '密码框',
        self::TYPE_DYNAMIC_INPUT => '动态文本域',
        self::TYPE_DYNAMIC_TEXTAREA => '动态多行文本域',
    ];

    // 搜索栏场景的字段类型
    public static $searchTypeMap = [
        self::TYPE_INPUT => '文本域',
        self::TYPE_INPUT_JSON => 'JSON文本域',
        self::TYPE_SINGLE => '单选',
        self::TYPE_DATETIME => '日期时间选择器',
        self::TYPE_CASCADER => '级联选择',
        self::TYPE_SELECT_TREE => '树状下拉选择',
    ];

    use ModelTree {
        ModelTree::allNodesQuery as parentAllNodesQuery;
    }

    protected $casts = [
        'parent_id' => 'integer',
        'order' => 'integer',
        'search_hide' => 'bool',
        'list_hide' => 'bool',
        'form_hide' => 'bool',
        'detail_hide' => 'bool',
        'is_virtual' => 'bool',
        'options' => \App\Admin\Casts\Json::class,
        'value' => \App\Admin\Casts\Json::class,
        'form_disabled' => 'bool',
    ];
    protected $fillable = [
        'parent_id',
        'order',
        'type',
        'name',
        'alias',
        'slug',
        'desc',
        'options',
        'value',
        'validation_rules',
        'filter_rules',
        'search_hide',
        'list_hide',
        'form_hide',
        'detail_hide',
        'deleted_at',
        'is_virtual',
        'form_disabled',
        'list_width',
        'list_fixed',
    ];
    protected $treeWithAuth = false;

    // 系统自带的模型
    public static $systemModels = [
        'admin_operation_logs' => [
            'name' => '操作日志',
        ],
        'admin_permissions' => [
            'name' => '权限',
        ],
        'admin_role_permission' => [
            'name' => null,
        ],
        'admin_roles' => [
            'name' => '角色',
        ],
        'admin_user_permission' => [
            'name' => null,
        ],
        'admin_user_role' => [
            'name' => null,
        ],
        'admin_users' => [
            'name' => '管理员',
        ],
        'api_document_categories' => [
            'name' => 'API文档分类',
        ],
        'api_documents' => [
            'name' => 'API文档',
        ],
        'config_categories' => [
            'name' => '配置分类',
        ],
        'configs' => [
            'name' => '配置',
        ],
        'failed_jobs' => [
            'name' => null,
        ],
        'jobs' => [
            'name' => null,
        ],
        'migrations' => [
            'name' => null,
        ],
        'password_resets' => [
            'name' => null,
        ],
        'system_media' => [
            'name' => '文件',
        ],
        'system_media_categories' => [
            'name' => '文件分类',
        ],
        'system_models' => [
            'name' => '系统模型',
        ],
        'telescope_entries' => [
            'name' => null,
        ],
        'telescope_entries_tags' => [
            'name' => null,
        ],
        'telescope_monitoring' => [
            'name' => null,
        ],
        'vue_admin_user_routers' => [
            'name' => '管理员路由',
        ],
        'vue_router_role' => [
            'name' => '路由角色',
        ],
        'vue_routers' => [
            'name' => '路由',
        ],
    ];    

    // 示例模型
    public static $demoModels = [
        'demos' => [
            'name' => '路由',
        ],
    ];

    // 搜索栏默认隐藏的字段
    public static $searchHideField = [
        'created_at',
        'updated_at',
    ];

    // 列表页默认隐藏的字段
    public static $listHideField = [
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    // 表单页默认隐藏的字段
    public static $formHideField = [
        'id',
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    // 详情页默认隐藏的字段
    public static $detailHideField = [
        
    ];

    // 列表页固定返回的字段
    public static $listReturnField = [
        'id',
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    // 自动赋值的字段
    public static $autoValueField = [
        'id',
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    /**
     * parent_id 默认为 0 处理
     *
     * @param $value
     */
    public function setParentIdAttribute($value)
    {
        $this->attributes['parent_id'] = $value ?: 0;
    }

    public function treeWithAuth()
    {
        $this->treeWithAuth = true;
        return $this;
    }

    protected function allNodesQuery(): Builder
    {
        return $this->parentAllNodesQuery()
            ->when($this->treeWithAuth, function (Builder $query) {
                $query->with('roles');
            });
    }

    protected function ignoreTreeNode($node): bool
    {
        // 不需要鉴权，或者有权限，则不忽略
        if (
            // 不需要鉴权
            !$this->treeWithAuth
        ) {
            return false;
        } else {
            return true;
        }
    }

    public function replaceFromFile(UploadedFile $file): array
    {
        $tree = json_decode(file_get_contents($file->getRealPath()), true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new SystemModelException(sprintf('JSON 数据解析错误 [ %s ]', json_last_error()));
        }

        $this->truncate();
        $flatten = $this->flatten($tree);
        foreach ($flatten as $key => $value) {
            try {
                DB::beginTransaction();
                $this->insert($value);
                DB::commit();
            } catch (Exception $e) {
                DB::rollback(); 
                throw new SystemModelException(sprintf('导入错误 [ %d-%s ]', $value['id'], $e->getMessage()));
            }
        }
        
        return $tree;
    }

    public function getTypeTextAttribute()
    {
        return static::$typeMap[$this->type] ?? '';
    }

    public function category()
    {
        return $this->belongsTo(ConfigCategory::class);
    }

    /**
     * 通过配置分类标识，获取所有配置
     *
     * @param string $categorySlug
     * @param bool $onlyValues
     *
     * @return Config[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection
     */
    public static function getByCategorySlug(string $categorySlug, bool $onlyValues = false)
    {
        $configs = static::whereHas('category', function (Builder $query) use ($categorySlug) {
            $query->where('slug', $categorySlug);
        })->get();

        if ($onlyValues) {
            return $configs->pluck('value', 'slug');
        } else {
            return $configs;
        }
    }

    /**
     * @param Config[]|\Illuminate\Support\Collection $configs
     * @param array $inputs slug => value 键值对
     *
     * @return Config[]|\Illuminate\Support\Collection
     */
    public static function updateValues($configs, $inputs)
    {
        $configs->each(function (Config $config) use ($inputs) {
            if (key_exists($config->slug, $inputs)) {
                $config->update(['value' => $inputs[$config->slug]]);
            }
        });

        return $configs->pluck('value', 'slug');
    }

    public static function getConfigValue(string $slug, $default = null)
    {
        return static::query()->where('slug', $slug)->value('value') ?? $default;
    }

    protected static function getConfigGroupsFromDB(): array
    {
        // 避免刚安装系统时，还没有数据库的情况
        try {
            $groups = ConfigCategory::query()
                ->select(['id', 'slug'])
                ->with('configs:category_id,slug,value')
                ->get()
                ->map(function (ConfigCategory $category) {
                    return [
                        'slug' => $category->slug,
                        'configs' => $category->configs->pluck('value', 'slug')->toArray(),
                    ];
                })
                ->pluck('configs', 'slug')
                ->toArray();
        } catch (Throwable $e) {
            report($e);
            $groups = [];
        }

        return $groups;
    }

    /**
     * 如果直接用 config 函数获取配置，则已经是服务提供者里被替换了的
     * 这里要获取原始的文件配置
     *
     * @return array
     */
    protected static function getConfigGroupsFromFile(): array
    {
        $configFilePath = app('path.config').'/'.static::CONFIG_KEY.'.php';

        $config = [];
        if (file_exists($configFilePath) && !is_array($config = include $configFilePath)) {
            $config = [];
        }

        return $config;
    }

    public static function getDottedConfigFromCache(): array
    {
        return Cache::rememberForever(static::CACHE_KEY, function () {
            return array_merge(
                static::dotConfigs(static::getConfigGroupsFromFile()),
                static::dotConfigs(static::getConfigGroupsFromDB())
            );
        });
    }

    protected static function dotConfigs(array $configs)
    {
        return Arr::dot($configs, static::CONFIG_KEY.'.');
    }

    public static function loadToConfig()
    {
        config(static::getDottedConfigFromCache());
    }

    public static function clearConfigCache()
    {
        Cache::forget(static::CACHE_KEY);
    }

    /**
     * 根据模型标识获取ID
     * @param String $slug
     */
    public static function getIdBySlug($slug){
        $slug = barToUnderline( $slug);
        return self::withTrashed(true)
            ->where('slug', $slug)
            ->where('parent_id', 0)
            ->value('id');
    }

    /**
     * 搜索匹配字段
     * @param String $name
     */
    public static function searchMapFields($name, $isVirtual=false){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型字段
        $fields = self::withTrashed(true)
            ->where('parent_id', $id)
            ->where('is_virtual', $isVirtual)
            ->orderBy('order')
            ->get(['slug','filter_rules'])
            ->toArray();
        $filters = [];
        foreach ($fields as $key => $value) {
            if ($value['filter_rules']) {
                $filters[$value['slug']] = json_decode($value['filter_rules'], true);
            } else {
                $filters[] = $value['slug'];
            }
        }
        return $filters;
    }

    /**
     * 表单验证规则
     * @param String $name
     */
    public function formValidationRules($name){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型字段
        return array_column(
            $this->where('parent_id', $id)
            ->where('form_hide', false)
            ->orderBy('order')
            ->get([
                'slug',
                DB::Raw('IFNULL(`validation_rules`,"") AS validation_rules')
            ])
            ->toArray(),
            'validation_rules',
            'slug'
        );
    }

    /**
     * 字段属性
     * @param String $name
     */
    public function fieldAttributes($name){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型字段
        return array_column(
            $this->where('parent_id', $id)
            ->get([
                'slug',
                DB::raw('IFNULL(alias, name) AS name')
            ])
            ->toArray(),
            'name',
            'slug'
        );
    }

    /**
     * 字段数据类型转换
     * @param String $name
     */
    public static function fieldCasts($name){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型字段
        $fields = self::where('parent_id', $id)
            ->where('is_virtual', 0)
            ->get(['slug','type','options'])
            ->toArray();
        foreach ($fields as $key => $value) {
            $fields[$key]['type'] = self::typeToCasts($value['type'],$value['options']);
        }
        return array_column($fields,'type','slug');
    }

    /**
     * 字段类型转数据类型
     * @param String $name
     */
    public static function typeToCasts($type, $options=null){
        $result = 'string';
        switch ($type) {
            case self::TYPE_TIME:
                $result = 'datetime:Y-m-d H:i:s';
                break;
            case self::TYPE_DATE:
            case self::TYPE_DATETIME:
                if (isset($options['format'])) {
                    switch ($options['format']) {
                        case 'datetime':
                            $result = 'string';
                            break;
                        case 'unixtime':
                            $result = \App\Admin\Casts\STRTOTIME::class;
                            break;
                    }
                }
                break;
            case self::TYPE_MULTIPLE:
            case self::TYPE_CASCADER:
                if (isset($options['format'])) {
                    switch ($options['format']) {
                        case 'json':
                            $result = \App\Admin\Casts\Json::class;
                            break;
                        case 'comma':
                            $result = \App\Admin\Casts\Comma::class;
                            break;
                    }
                }
                break;
            case self::TYPE_FILE:
                $result = \App\Admin\Casts\Json::class;
                break;
            case self::TYPE_PASSWORD:
                $result = \App\Admin\Casts\Password::class;
                break;
            case self::TYPE_INPUT_JSON:
                $result = \App\Admin\Casts\Json::class;
                break;
            default:
                $result = 'string';
                break;
        }
        return $result;
    }

    /**
     * 字段类型模拟数据
     * @param String $modelName
     * @param Array $field
     */
    public static function fieldAnalogData($modelName,$field){
        $fieldType = DB::connection()
            ->getDoctrineColumn($modelName, $field['slug'])
            ->getType()
            ->getName();
        $result = null;
        switch ($fieldType) {
            case 'smallint':
            case 'bigint':
            case 'numeric':
            case 'integer':
                $result = 1;
                break;
            case 'decimal':
            case 'float':
                $result = 1.00;
                break;
            case 'string':
            case 'text':
            case 'blob':
            case 'guid':
                $result = $field['name'];
                break;
            case 'date':
                $result = '2022-02-02';
                break;
            case 'datetime':
                $result = '2022-02-02 02:02:02';
                break;
            case 'datetimetz':
                $result = '2022-02-02 02:02:02 UTC';
                break;
            case 'time':
                $result = '02:02:02';
                break;
            case 'boolean':
                $result = 1;
                break;
        }
        switch ($field['type']) {
            case self::TYPE_DATE:
                $result = '2022-02-02';
                break;
            case self::TYPE_TIME:
                $result = '02:02:02';
                break;
            case self::TYPE_DATETIME:
                $result = '2022-02-02 02:02:02';
                break;
            case self::TYPE_FILE:
                $result = [
                    'id'=>1,
                    'origin_filename'=>'1.png',
                    'path'=>'uploads/1.png'
                ];
                break;
        }
        return $result;
    }

    /**
     * 字段赋默认值
     */
    public function treeSystemModels($parent_id=null){
        if ($parent_id) {
            $ids = $this->getModelId($parent_id);
            $tree = $this->treeInclude($ids)->toTree();
        } else {
            $tree = $this->toTree();
        }
        $validationRules = [];
        $filterRules = [];
        $fieldTypes = [];
        $fields = [];
        foreach($tree as $key => $value){
            $fields[$value['id']] = [];
            foreach ($value['children'] as $key2 => $value2) {
                if (isset($value2['options']['sample']) && $value2['options']['sample']==3) {
                    $config = Config::find($value2['options']['options']);
                    $tree[$key]['children'][$key2]['options']['options'] = $config['name'];
                }
                if ($value2['value'] && !$value2['is_virtual']) {
                    $options['options'] = parseOptions($value2, 'list');
                }
                $tree[$key]['children'][$key2]['filter_rules'] = $tree[$key]['children'][$key2]['filter_rules'] ?:  '["equal","?"]';
                if (!$value2['is_virtual']) {
                    array_push($fields[$value['id']], $value2['slug']);
                }
            }
            $validationRules[$value['id']] = self::getValidationRules($tree[$key]['children']);
            $filterRules[$value['id']] = self::getFilterRules($tree[$key]['children']);
            $fieldTypes[$value['id']] = self::getFieldTypes($tree[$key]['children']);
        }
        return [
            'tree'=>$tree,
            'validationRules'=>$validationRules,
            'filterRules'=>$filterRules,
            'fieldTypes'=>$fieldTypes,
            'fields'=>$fields,
        ];
    }

    /**
     * 获取单选字段的对应的值
     * @param String $name
     */
    public static function getSingleSelectValue($name,$field,$key){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型字段
        $options = self::where('parent_id', $id)
            ->where('slug', $field)
            ->value('options');
        $options = parseOptions($options, 'list');
        return $options['options'][$key];
    }

    /**
     * 获取模型字段标识
     * @param String $name
     * @param String $scene
     */
    public static function getFields($name, $scene='list'){
        if (!in_array($scene, ['list','form','search','detail'])) {
            return [];
        }
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型字段
        $field = self::where('parent_id', $id)
            ->where($scene.'_hide', false)
            ->where('is_virtual', false)
            ->pluck('slug')
            ->toArray();
        if ($scene=='list') {
            // 合并列表页固定返回的字段
            $field = array_merge($field, self::$listReturnField);
        }
        // 虚拟字段
        $virtualField = self::where('parent_id', $id)
            ->where($scene.'_hide', false)
            ->where('is_virtual', true)
            ->whereNotNull('value')
            ->get(DB::raw("concat(value,' as ',slug) as slug"))
            ->pluck('slug')
            ->toArray();
        foreach ($virtualField as $key => $value) {
            $value = str_replace('"', "", $value);
            $virtualField[$key] = DB::raw($value);
        }
        return array_merge($field, $virtualField);
    }

    /**
     * 获取虚拟模型字段标识
     * @param String $name
     * @param String $scene
     */
    public static function getVirtualFields($name, $scene='list'){
        if (!in_array($scene, ['list','search'])) {
            return [];
        }
        // 模型ID
        $id = self::getIdBySlug($name);
        // 虚拟字段
        $virtualField = self::where('parent_id', $id)
            ->where($scene.'_hide', false)
            ->where('is_virtual', true)
            ->whereNotNull('value')
            ->pluck('slug')
            ->toArray();
        return $virtualField;
    }

    /**
     * 获取虚拟字段列表默认值
     * @param String $name
     * @param String $slug
     */
    public static function getVirtualFieldValue($name, $slug){
        // 模型ID
        $id = self::getIdBySlug($name);
        return self::where('parent_id', $id)
            ->where('slug', $slug)
            ->value('value');
    }

    /**
     * 获取验证规则（排除虚拟字段）
     * @param Array $arr
     */
    public static function getValidationRules($arr){
        $validationRules = [];
        foreach ($arr as $key => $value) {
            if (!$value['is_virtual'] && !in_array($value['slug'], self::$autoValueField)) {
                $validationRules[$value['slug']] = $value['validation_rules'] ?: "";
            }
        }
        return $validationRules;
    }

    /**
     * 获取筛选规则（排除虚拟字段）
     * @param Array $arr
     */
    public static function getFilterRules($arr){
        $filterRules = [];
        foreach ($arr as $key => $value) {
            if (!$value['is_virtual']) {
                if ($value['filter_rules']) {
                    $filterRules[$value['slug']] = json_decode($value['filter_rules'], true);
                } else {
                    $filterRules[$value['slug']] = "";
                }
            }
        }
        return $filterRules;
    }

    /**
     * 获取字段类型（排除虚拟字段）
     * @param Array $arr
     */
    public static function getFieldTypes($arr){
        $fieldTypes = [];
        foreach ($arr as $key => $value) {
            if (in_array($value['slug'], self::$listHideField)) {
                $value['type'] = 'time';
            }
            if (!$value['is_virtual']) {
                if ($value['type']) {
                    $fieldTypes[$value['slug']] = self::typeToCasts($value['type'],$value['options']);
                } else {
                    $fieldTypes[$value['slug']] = "";
                }
            }
        }
        return $fieldTypes;
    }

    /**
     * 获取模型下的字段
     * @param Int $parent_id
     */
    public static function childrenField($parent_id){
        return self::query()
            ->where('parent_id', $parent_id)
            ->orderBy('order')
            ->get([
                '*',
                DB::raw("IFNULL(`filter_rules`, '[\"equal\",\"?\"]') AS filter_rules")
            ])
            ->toArray();
    }

    /**
     * 获取模型下各个场景的字段（排除虚拟字段）
     * @param Array $systemModel
     */
    public static function groupSceneField($systemModel){
        $listFields = [];
        $searchFields = [];
        $formFields = [];
        $detailFields = [];
        foreach ($systemModel as $key => $value) {
            if (!$value['is_virtual']) {
                if (!$value['list_hide']) {
                    $listFields[] = $value['slug'];
                }
                if (!$value['search_hide']) {
                    $searchFields[] = $value['slug'];
                }
                if (!$value['form_hide']) {
                    $formFields[] = $value['slug'];
                }
                if (!$value['detail_hide']) {
                    $detailFields[] = $value['slug'];
                }
            }
        }
        return  [
            'listFields' => $listFields,
            'searchFields' => $searchFields,
            'formFields' => $formFields,
            'detailFields' => $detailFields,
        ];
    }

    /**
     * 字段类型排序
     * @param Array $typeMap
     */
    public static function typeMapSort($typeMap){
        $typeGroup = self::query()
            ->select(DB::raw("count(*) as count, type"))
            ->whereNotNull('type')
            ->orderByDesc('count')
            ->groupBy('type')
            ->get()
            ->toArray();
        $typeGroup = array_column($typeGroup, 'type');
        return array_merge(orderByArray($typeMap, $typeGroup ,true), $typeMap);
    }

    /**
     * 验证规则排序
     * @param Array $validationRuleMap
     */
    public static function validationRuleMapSort($validationRuleMap){
        foreach ($validationRuleMap as $key => $value) {
            $validationRuleMap[$key]['count'] = self::query()
                ->where('validation_rules', 'like', "%{$value['key']}%")
                ->count();
        }
        $validationRuleMap = array_key_sort($validationRuleMap, 'count', SORT_DESC);
        return $validationRuleMap;
    }

    /**
     * 关联模型排序
     * @param Array $models
     */
    public static function modelSort($models){
        $existModels = [];
        foreach ($models as $key => $value) {
            $existModels[$value] = self::query()
                ->where('options', 'like', "%\"{$value}\"%")
                ->count();
        }
        arsort($existModels);
        return array_keys($existModels);
    }

    /**
     * 所有字段
     * @param Int $parent_id
     * @param Int $id
     */
    public function fields($parent_id){
        return $this->where('parent_id', $parent_id)
            ->orderBy('id')
            ->get([
                'id',
                'slug',
                DB::raw('IFNULL(alias, name) AS name')
            ]);
    }

    public static function formatReturnParam($name, $fieldId=null){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型名称
        $modelName = self::withTrashed(true)
            ->where('parent_id', 0)
            ->where('id', $id)
            ->value('slug');
        // 模型字段
        // 排除表单页默认隐藏的字段
        $fields = self::withTrashed(true)
            ->where('parent_id', $id);
        if ($fieldId) {
            $fields = $fields->where('id', $fieldId);
        }
        $fields = $fields->orderBy('order')
            ->get([
                'slug',
                'type',
                DB::raw('IFNULL(alias, name) AS name'),
                'options'
            ])
            ->toArray();
        $str = "";
        foreach ($fields as $key => $value) {
            if (in_array($value['type'], ['single','multiple']) && $value['options']['sample']=='1') {
                $value['name'] = $value['name'].":".str_replace("\n", "<br/>", $value['options']['options']);
            }
            $tab = "";
            $newLine = PHP_EOL;
            if ($key==0) $tab = "";
            if ($key==count($fields)-1) $newLine = "";
            $str .= $tab."* @return_param ".$value['slug']." string ".$value['name'].$newLine;
        }
        return $str;
    }

    public static function formatParam($name, $fieldId=null){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型名称
        $modelName = self::withTrashed(true)
            ->where('parent_id', 0)
            ->where('id', $id)
            ->value('slug');
        // 模型字段
        // 排除表单页默认隐藏的字段
        $fields = self::withTrashed(true)
            ->where('parent_id', $id);
        if ($fieldId) {
            $fields = $fields->where('id', $fieldId);
        }
        $fields = $fields->whereNotIn('slug', self::$formHideField)
            ->orderBy('order')
            ->get([
                'slug',
                'type',
                DB::raw('IFNULL(alias, name) AS name'),
                'options'
            ])
            ->toArray();
        $str = "";
        foreach ($fields as $key => $value) {
            $fieldAnalogData = self::fieldAnalogData($modelName, $value);
            $type = gettype($fieldAnalogData);
            if (
                in_array($value['type'], ['single','multiple']) && 
                $value['options']['sample']=='1'
            ) {
                $value['name'] = $value['name'].":".str_replace("\n", "<br/>", $value['options']['options']);
            }
            $tab = "";
            $newLine = PHP_EOL;
            if ($key==0) $tab = "";
            if ($key==count($fields)-1) $newLine = "";
            $str .= "$tab* @param {$value['slug']} 可选 {$type} {$value['name']} $newLine";
        }
        return $str;
    }

    public static function formatJsonParam($name){
        // 模型ID
        $id = self::getIdBySlug($name);
        // 模型名称
        $modelName = self::withTrashed(true)
            ->where('parent_id', 0)
            ->where('id', $id)
            ->value('slug');
        // 模型字段
        // 排除表单页默认隐藏的字段 
        $fields = self::withTrashed(true)
            ->where('parent_id', $id)
            ->whereNotIn('slug', self::$formHideField)
            ->orderBy('order')
            ->get([
                'slug',
                'type',
                DB::raw('IFNULL(alias, name) AS name'),
                'options'
            ])
            ->toArray();
        $arr = [];
        foreach ($fields as $key => $value) {
            $arr[$value['slug']] = self::fieldAnalogData($modelName, $value);
        }     
        // 使用正则表达式将换行符和空格删除
        $json = json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
        $compressedJson = preg_replace_callback('/(?<!\\\\) "(?: \\\\["\\\\]|[^"])*"(*SKIP)(*F)|\s+/s', function($matches) {
            return preg_replace('/\s+/', ' ', $matches[0]);
        }, $json);
        return '* @json_param '.$compressedJson;
    }

    // 更新 showdoc 的请求和返回参数
    public function updateParam(){
        // 生产环境下不适用
        if (config()->get('app.env')=='production') {
            return false;
        }
        $filenames = [
            app_path().'/Admin/Showdocs/'.Str::singular(Str::studly($this->parent->slug)).'Showdoc.php',
            app_path().'/Home/Showdocs/'.Str::singular(Str::studly($this->parent->slug)).'Showdoc.php'
        ];
        foreach ($filenames as $filename) {
            if (!file_exists($filename)) {
                continue;
            }
            // 读取文件并对每一行进行处理回调
            $lines = file($filename, FILE_IGNORE_NEW_LINES);// 读取文件并忽略行末的换行符
            foreach ($lines as $key => $line) {
                if (strpos($line, '* @param '.$this->slug) === 0) {
                    // 替换param
                    $lines[$key] = SystemModel::formatParam($this->parent->slug, $this->id);
                } elseif (strpos($line, '* @return_param '.$this->slug) === 0) {
                    // 替换return_param
                    $lines[$key] = SystemModel::formatReturnParam($this->parent->slug, $this->id);
                }
            }
            // 重新组合文本并写回文件
            $text = implode("\n", $lines);
            file_put_contents($filename, $text);
        }
    }

    // 获取某个模型的ID以及它的子ID
    public function getModelId($parent_id){
        $ids = $this->where('parent_id', $parent_id)->pluck('id')->toArray();
        return array_merge($ids, [$parent_id]);
    }
}
